using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

namespace BTEditor
{
    public static class BTUtils
    {
        public static string GenerateUniqueStringID()
        {
            return Guid.NewGuid().ToString("N");
        }
        
        public static string GetTypeName(string fullName)
        {
            string str = fullName.Substring(fullName.IndexOf('.') + 1);
            return str;
        }
        
        public static string GetTypeName(Type type)
        {
            return GetTypeName(type.FullName);
        }
        
        public static void DrawBezier(Rect a, Rect b)
        {
            Color color = Color.blue;
            DrawBezier(a.center, b.center, color);
        }

        public static void DrawBezier(Vector2 a, Vector2 b, Color color)
        {
            Vector2 start = a.x <= b.x ? a : b;
            Vector2 end = a.x <= b.x ? b : a;

            float vertDistance = Mathf.Abs(start.y - end.y);
            float horzDistance = Mathf.Abs(start.x - end.x);
            float lerp = Mathf.Min(Mathf.Clamp01(vertDistance / BTEditorConst.MIN_V_DISTANCE), Mathf.Clamp01(horzDistance / BTEditorConst.MIN_H_DISTANCE));
            float offset = Mathf.Lerp(0.0f, BTEditorConst.BEZIER_H_OFFSET, lerp);

            Vector3 startTangent = new Vector3(start.x + offset, start.y, 0);
            Vector3 endTangent = new Vector3(end.x - offset, end.y, 0);

            Handles.DrawBezier(start, end, startTangent, endTangent, color, null, BTEditorConst.BEZIER_WIDTH);
        }
        
         public static void ShowMenuClick(GenericMenu genericMenu,bool isCanNotAddNode)
        {
            if (BTEditorProperty.Instance.SelectNodeCount == 0)
            {
                return;
            }
            if (BTEditorProperty.Instance.SelectNodeCount > 1)
            {
                return;
            }
            BTNode btNode = BTEditorProperty.Instance.DefaultNode;
            if (btNode.IsHaveChild && btNode.IsRoot)
            {
                return;
            }

            switch (btNode.NodeEnum)
            {
                case EditorNodeEnum.Composite:
                    if (!isCanNotAddNode)
                    {
                        AddNode(genericMenu, btNode,"Task", BTEditorProperty.Instance.TaskDic);
                        AddNode(genericMenu, btNode,"Decorator",BTEditorProperty.Instance.DecoratorDic);
                        AddNode(genericMenu, btNode,"Composite",BTEditorProperty.Instance.CompositeDic);
                    }
                    AddSwitch(genericMenu,Enum.GetName(typeof(EditorNodeEnum),EditorNodeEnum.Composite), btNode, BTEditorProperty.Instance.CompositeDic);
                    AddSwitch(genericMenu,Enum.GetName(typeof(EditorNodeEnum),EditorNodeEnum.Decorator), btNode, BTEditorProperty.Instance.DecoratorDic);
                    break;
                case EditorNodeEnum.Decorator:
                    AddSwitch(genericMenu,Enum.GetName(typeof(EditorNodeEnum),EditorNodeEnum.Decorator), btNode, BTEditorProperty.Instance.DecoratorDic);
                    AddSwitch(genericMenu,Enum.GetName(typeof(EditorNodeEnum),EditorNodeEnum.Composite), btNode, BTEditorProperty.Instance.CompositeDic);
                    if (!isCanNotAddNode)
                    {
                        AddNode(genericMenu, btNode,"Task", BTEditorProperty.Instance.TaskDic);
                        AddNode(genericMenu, btNode,"Decorator",BTEditorProperty.Instance.DecoratorDic);
                        AddNode(genericMenu, btNode,"Composite",BTEditorProperty.Instance.CompositeDic);
                    }
                    break;
                case EditorNodeEnum.Task:
                    AddSwitch(genericMenu,Enum.GetName(typeof(EditorNodeEnum),EditorNodeEnum.Task), btNode,BTEditorProperty.Instance.TaskDic);
                    break;
                case EditorNodeEnum.Root:
                    AddNode(genericMenu, btNode,"Task", BTEditorProperty.Instance.TaskDic);
                    AddNode(genericMenu, btNode,"Decorator",BTEditorProperty.Instance.DecoratorDic);
                    AddNode(genericMenu, btNode,"Composite",BTEditorProperty.Instance.CompositeDic);
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
            genericMenu.ShowAsContext();
        }
        
        private static void AddSwitch(GenericMenu genericMenu,string nodeRoot,BTNode btNode,Dictionary<string,Type> nodeDic)
        {
            foreach (KeyValuePair<string, Type> keyValuePair in nodeDic)
            {
                if (IsRootNode(keyValuePair.Key))
                {
                    continue;
                }
                if (keyValuePair.Value != btNode.NodeType)
                {
                    genericMenu.AddItem(new GUIContent($"Switch To/{nodeRoot}/{keyValuePair.Key}"),false, () =>
                    {
                        SwitchNodeTo(btNode,keyValuePair.Value,keyValuePair.Key);
                    });
                }           
            }         
        }
        
        public static bool IsRootNode(string node)
        {
            return node == "Root";
        }
        
        private static void AddNode(GenericMenu genericMenu,BTNode btNode,string rooName,Dictionary<string,Type> nodeDic)
        {
            foreach (KeyValuePair<string,Type> keyValuePair in nodeDic)
            {
                if (IsRootNode(keyValuePair.Key))
                {
                    continue;
                }
                genericMenu.AddItem(new GUIContent($"{rooName}/{keyValuePair.Key}"),false, () =>
                {
                    CreateNode(keyValuePair.Value, btNode);
                });
            } 
        }

        public static void SwitchNodeTo(BTNode btNode,Type type,string newLabel)
        {
            EditorNode node = Activator.CreateInstance(type) as EditorNode;
            btNode.SetEditorNode(node);
            btNode.Label = newLabel;
        }

        public static EditorNode CreateNode(Type type,BTNode parent)
        {
            if (Activator.CreateInstance(type) is EditorNode node)
            {
                BTNode child = BTNodeFactory.CreateNode(GetTypeName(type.FullName), node,
                    new Vector2(parent.RealRect.x, parent.RealRect.y + 200));
                parent.AddChild(child);
                BTEditorProperty.Instance.AddLine(parent, child);
                return node;
            }

            return null;
        }
    }
}